package cn.tedu.knows.sys.interceptor;

import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Resource
    private RestTemplate restTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //JWT令牌会在用户请求中
        // 我们需要在当前拦截器中获得者JWT令牌
        String token=request.getParameter("accessToken");
        //借助授权服务器提供的解析Jwt的方法获得用户详情对象
        String url=
           "http://auth-service/oauth/check_token?token={1}";
        Map<String,Object> map=
                restTemplate.getForObject(url, Map.class,token);
        //要想获得用户名:map.get("user_name")
        //要想获得用户权限:map.get("authorities")
        //默认情况下map.get("authorities") 被解析为一个List
        //获得用户所有权限的List
        List<String> list=(List<String>)map.get("authorities");
        //UserDetails赋值时需要的是String类型的数组
        // 所以将list转换为数组类型
        String[] auth=list.toArray(new String[0]);
        // 构建UserDetails对象
        UserDetails userDetails= User.builder()
                .username(map.get("user_name").toString())
                .password("")
                .authorities(auth)
                .build();
        //我们要将上面的用户详情,保存到Spring Security中
        // 目标是控制器方法参数@AuthenticationPrincipal可以获得用户详情
        // Spring Security框架给定了方法来完成这个目标
        PreAuthenticatedAuthenticationToken authenticationToken=
                new PreAuthenticatedAuthenticationToken(
                        userDetails,userDetails.getPassword(),
                        AuthorityUtils.createAuthorityList(auth)
                );
        //将本次解析的用户详情和当前请求关联
        //关联之后才能在后面的控制器中获得用户详情
        authenticationToken.setDetails(
                new WebAuthenticationDetails(request));
        //将authenticationToken赋值到SpringSecurity容器
        SecurityContextHolder.getContext()
                .setAuthentication(authenticationToken);
        //别忘了返回true!!!!
        return true;
    }
}





